package com.xyy.saas.payment.api.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.xyy.address.dto.XyyRegionBusinessDto;
import com.xyy.address.dto.XyyRegionParams;
import com.xyy.framework.redis.core.RedisClient;
import com.xyy.saas.payment.adpater.RouteManager;
import com.xyy.saas.payment.adpater.assemble.dto.WithdrawAccountDto;
import com.xyy.saas.payment.adpater.fumin.config.FuminBankCodeConfig;
import com.xyy.saas.payment.adpater.fumin.config.MerchantCategoryConfig;
import com.xyy.saas.payment.adpater.impl.PinganAdapter;
import com.xyy.saas.payment.common.Constants;
import com.xyy.saas.payment.common.enums.PictureEnum;
import com.xyy.saas.payment.common.exception.PaymentException;
import com.xyy.saas.payment.common.service.RegionService;
import com.xyy.saas.payment.cores.api.PaymentMerchantApi;
import com.xyy.saas.payment.cores.bo.*;
import com.xyy.saas.payment.cores.enums.AccountTypeEnum;
import com.xyy.saas.payment.cores.enums.BusinessTypeEnum;
import com.xyy.saas.payment.cores.enums.CertTypeEnum;
import com.xyy.saas.payment.cores.enums.ResultCodeEnum;
import com.xyy.saas.payment.cores.param.*;
import com.xyy.saas.payment.cores.vo.*;
import com.xyy.saas.payment.cores.vo.SettleOrderVo2;
import com.xyy.saas.payment.dao.model.PayAccount;
import com.xyy.saas.payment.dao.model.SubBankCode;
import com.xyy.saas.payment.merchant.core.dto.*;
import com.xyy.saas.payment.merchant.core.service.BaseBankService2;
import com.xyy.saas.payment.merchant.core.service.SeparateOrderService2;
import com.xyy.saas.payment.merchant.core.service.UserInfoService2;
import com.xyy.saas.payment.merchant.core.vo.*;
import com.xyy.saas.payment.merchant.core.vo.AccountDto;
import com.xyy.saas.payment.payment.core.dto.ActiveCodeDto;
import com.xyy.saas.payment.service.PayAccountService;
import com.xyy.saas.payment.service.SubBankCodeService;
import com.xyy.saas.payment.settle.core.service.AccountService;
import com.xyy.saas.payment.util.ApolloUtil;
import com.xyy.saas.payment.util.JSONUtils;
import com.xyy.saas.payment.util.RedisUtil;
import com.xyy.saas.payment.util.SignUtil;
import com.xyy.util.StringUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn;

import javax.annotation.Resource;
import java.util.*;

@DependsOn("apolloUtil")
@Service(version = "1.0.0")
public class PaymentMerchantApiImpl implements PaymentMerchantApi {
    private static final Logger LOGGER = LoggerFactory.getLogger(PaymentMerchantApiImpl.class);

    @Autowired
    private AccountService accountService;
    @Autowired
    private RedisClient redisClient;
    @Autowired
    private SubBankCodeService subBankCodeService;
    @Autowired
    private FuminBankCodeConfig fuminBankCodeConfig;
    @Resource
    private RouteManager routeManager;
    @Resource
    private UserInfoService2 userInfoService2;
    @Resource
    private BaseBankService2 baseBankService2;
    @Resource
    private RegionService regionService;
    @Resource
    private SeparateOrderService2 separateOrderService2;
    @Autowired
    private PinganAdapter pinganAdapter;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private PayAccountService payAccountService;

    @Override
    public ResultVO createAccount(AccountVo accountVo, String sign) {
        ResultVO resultVO;
        LOGGER.info("PaymentMerchantApiImpl createAccount begin accountVo:{}, sign:{}", JSON.toJSON(accountVo), sign);
        try{
            checkCreateAccountParam(accountVo, sign);
            AccountDto accountDto = new AccountDto();
            accountDto.setBusinessIdType(accountVo.getBusinessIdType().getType());
            accountDto.setBusinessUserId(accountVo.getBusinessId());
            resultVO = accountService.createAccount(accountDto);
            LOGGER.info("PaymentMerchantApiImpl createAccount end accountVo:{}", JSON.toJSON(accountVo));
            return resultVO;
        }catch (PaymentException e){
            LOGGER.error("PaymentMerchantApiImpl createAccount error accountVo:{}", JSON.toJSON(accountVo), e);
            resultVO = new ResultVO();
            resultVO.setCode(e.getErrCode());
            resultVO.setMsg(e.getErrMsg());
            return resultVO;
        }catch (Exception e){
            LOGGER.error("PaymentMerchantApiImpl createAccount error accountVo:{}", JSON.toJSON(accountVo), e);
            return ResultVO.createError(e.getMessage());
        }
    }

    @Override
    public ResultVO createAccountNew(AccountVoV1 accountVo, String sign) {
        ResultVO resultVO;
        LOGGER.info("PaymentMerchantApiImpl createAccountNew begin accountVo:{}, sign:{}", JSON.toJSON(accountVo), sign);
        try{
            checkCreateAccountParam(accountVo, sign);
            AccountDto accountDto = new AccountDto();
            accountDto.setBusinessIdType(accountVo.getBusinessIdType());
            accountDto.setBusinessUserId(accountVo.getBusinessId());
            resultVO = accountService.createAccount(accountDto);
            LOGGER.info("PaymentMerchantApiImpl createAccountNew end accountVo:{}", JSON.toJSON(accountVo));
            return resultVO;
        }catch (PaymentException e){
            LOGGER.error("PaymentMerchantApiImpl createAccountNew error accountVo:{}", JSON.toJSON(accountVo), e);
            resultVO = new ResultVO();
            resultVO.setCode(e.getErrCode());
            resultVO.setMsg(e.getErrMsg());
            return resultVO;
        }catch (Exception e){
            LOGGER.error("PaymentMerchantApiImpl createAccountNew error accountVo:{}", JSON.toJSON(accountVo), e);
            return ResultVO.createError(e.getMessage());
        }
    }

    @Override
    public ResultVO<String> createCPEAccount(AccountVo accountVo, String sign) {
        ResultVO resultVO;
        LOGGER.info("PaymentMerchantApiImpl createCPEAccount begin accountVo:{}, sign:{}", JSON.toJSON(accountVo), sign);
        try{
            checkCreateAccountParam(accountVo, sign);
            AccountDto accountDto = new AccountDto();
            accountDto.setBusinessIdType(accountVo.getBusinessIdType().getType());
            accountDto.setBusinessUserId(accountVo.getBusinessId());
            resultVO = accountService.createCPEAccount(accountDto);
            LOGGER.info("PaymentMerchantApiImpl createCPEAccount end accountVo:{}", JSON.toJSON(accountVo));
            return resultVO;
        }catch (PaymentException e){
            LOGGER.error("PaymentMerchantApiImpl createAccount error accountVo:{}", JSON.toJSON(accountVo), e);
            resultVO = new ResultVO();
            resultVO.setCode(e.getErrCode());
            resultVO.setMsg(e.getErrMsg());
            return resultVO;
        }catch (Exception e){
            LOGGER.error("PaymentMerchantApiImpl createAccount error accountVo:{}", JSON.toJSON(accountVo), e);
            return ResultVO.createError(e.getMessage());
        }
    }

    @Override
    public ResultVO<String> personalCertifyAccountCreate(PersonalAccountCreateVo personalAccountCreateVo, String sign) {
        ResultVO resultVO = new ResultVO();
        LOGGER.info("PaymentMerchantApiImpl personalAccountCreateVo begin personalAccountCreateVo:{}, token:{}", JSONUtils.toJSON(personalAccountCreateVo), personalAccountCreateVo.getName());

        //防止连点 value随便设置
        if(!StringUtil.isEmpty(redisClient.get("personalAccountCreateVo"+personalAccountCreateVo.getName()))) {
            resultVO.setCode(ResultCodeEnum.NOT_CONTINUOUS_CLICK.getCode());
            resultVO.setMsg(ResultCodeEnum.NOT_CONTINUOUS_CLICK.getDisplayMsg());
            return resultVO;
        }

        redisClient.set("merchantCreate"+personalAccountCreateVo.getName(), "1", 5L);

        try {
            String type = personalAccountCreateVo.getBusinessIdType().contains(BusinessTypeEnum.YIKUAIQIAN.getType()) ? Constants.YOP : Constants.PINGAN;
            String accountId = null;
            AccountDto accountDto = new AccountDto();
            accountDto.setBusinessIdType(personalAccountCreateVo.getBusinessIdType());
            accountDto.setBusinessUserId(personalAccountCreateVo.getBusinessUserId());
            ResultVO accountResult = accountService.createAccount(accountDto);

            if(!accountResult.getCode().equals(ResultCodeEnum.SUCCESS.getCode())) {
                accountId = accountResult.getResult().toString();
            }
            else {
                PayAccount payAccount = JSONUtils.parse2Object(accountResult.getResult().toString(), PayAccount.class);
                accountId = payAccount.getAccountId();
            }

            accountService.createThirdUserId(accountId, type, Constants.PERSONAL, personalAccountCreateVo.getOpenBank(), "");
            UserDto userDto = new UserDto();
            userDto.setThirdChannelType(type);
            Map<String, String> picMap = new HashMap<>(8);
            picMap.put(String.valueOf(PictureEnum.PERSONAL_CERT_FRONT.getCode()), personalAccountCreateVo.getPersonalIdCardFrontUrl());
            picMap.put(String.valueOf(PictureEnum.PERSONAL_CERT_BACK.getCode()), personalAccountCreateVo.getPersonalIdCardBackUrl());

            if(StringUtils.isNotBlank(personalAccountCreateVo.getCertificateUrl())) {
                picMap.put(String.valueOf(PictureEnum.AUTH_PIC.getCode()), personalAccountCreateVo.getCertificateUrl());
            }

            accountService.UserInfoPicChange(accountId, picMap);
            userDto.setPicMap(picMap);
            userDto.setAccountType(AccountTypeEnum.CUSTOMER.getType());
            userDto.setPicFmt(personalAccountCreateVo.getPicFmt());
            userDto.setBusinessIdType(personalAccountCreateVo.getBusinessIdType());
            userDto.setUserId(accountId);
            userDto.setBusinessIdType(personalAccountCreateVo.getBusinessIdType());
            //创建账户
            userDto.setName(personalAccountCreateVo.getName());
            userDto.setMobile(personalAccountCreateVo.getMobile());
            userDto.setAddress(personalAccountCreateVo.getAddress());
            userDto.setExtraMap(personalAccountCreateVo.getExtra());

            IdentityInfo identityInfo = new IdentityInfo();
            identityInfo.setId(personalAccountCreateVo.getCardId());
            identityInfo.setType(CertTypeEnum.ID_CARD.getCode());
            identityInfo.setValidUntil(personalAccountCreateVo.getValidUntil());
            identityInfo.setValidFrom(personalAccountCreateVo.getValidFrom());
            identityInfo.setProfession(personalAccountCreateVo.getProfession());
            identityInfo.setBusinessProvince(personalAccountCreateVo.getBusinessProvince());
            identityInfo.setBusinessCity(personalAccountCreateVo.getBusinessCity());
            identityInfo.setBusinessDistrict(personalAccountCreateVo.getBusinessDistrict());
            identityInfo.setBusinessAddress(personalAccountCreateVo.getBusinessAddress());
            userDto.setIdentityInfo(identityInfo);

            userDto.setBusinessIdType(personalAccountCreateVo.getBusinessIdType());

            SettleAccountDto settleAccountDto = new SettleAccountDto();
            Recipient recipient = new Recipient();
            recipient.setAccount(personalAccountCreateVo.getAccount());
            recipient.setName(personalAccountCreateVo.getSettleName());
            recipient.setMobile(personalAccountCreateVo.getSettleMobile());
            recipient.setOpenBank(personalAccountCreateVo.getOpenBank());
            recipient.setOpenBankCode(personalAccountCreateVo.getOpenBankCode());
            recipient.setCardType(personalAccountCreateVo.getCardType());
            recipient.setSubBank(personalAccountCreateVo.getSubBank());
            recipient.setSubBankCode(personalAccountCreateVo.getSubBankCode());
            settleAccountDto.setUserId(accountId);
            settleAccountDto.setRecipient(recipient);
            settleAccountDto.setBusinessIdType(personalAccountCreateVo.getBusinessIdType());
            settleAccountDto.setAccountType(AccountTypeEnum.CUSTOMER.getType());
            settleAccountDto.setCallbackAddress(personalAccountCreateVo.getCallbackAddress());
            settleAccountDto.setBusinessUserName(personalAccountCreateVo.getBusinessUserName());
            userDto.setSettleAccountDto(settleAccountDto);
            userDto.setOldBusinessUserId(personalAccountCreateVo.getOldBusinessUserId());

            if(checkUserNameAndCarUserName(resultVO, userDto)) return resultVO;

            resultVO = accountService.createAccount(userDto, personalAccountCreateVo.getBusinessIdType(), Constants.PERSONAL, personalAccountCreateVo.getAccountChannel());

            if(!ResultCodeEnum.SUCCESS.getCode().equals(resultVO.getCode())) {
                LOGGER.error("PaymentMerchantApiImpl personalAccountCreateVo create account error merchantAccountVo:{}", JSONUtils.toJSON(personalAccountCreateVo));
                return resultVO;
            }

            //上传图片
            resultVO = accountService.uploadPic(userDto, personalAccountCreateVo.getBusinessIdType(), personalAccountCreateVo.getAccountChannel());

            if(!ResultCodeEnum.SUCCESS.getCode().equals(resultVO.getCode())) {
                LOGGER.error("PaymentMerchantApiImpl personalAccountCreateVo upload error merchantAccountVo:{}", JSONUtils.toJSON(personalAccountCreateVo));
                return resultVO;
            }

            LOGGER.info("PaymentMerchantApiImpl personalAccountCreateVo end token:{}", personalAccountCreateVo.getName());
            return resultVO;
        }
        catch(Exception e) {
            LOGGER.error("PaymentMerchantApiImpl personalAccountCreateVo error merchantAccountVo =" + JSONUtils.toJSON(personalAccountCreateVo), e);

            if(e instanceof PaymentException) {
                resultVO.setCode(((PaymentException) e).getErrCode());
                resultVO.setMsg(((PaymentException) e).getErrMsg());
            }
            else {
                resultVO.setCode(ResultCodeEnum.DEFAULT_ERROR.getCode());
                resultVO.setMsg(ResultCodeEnum.DEFAULT_ERROR.getDisplayMsg());
            }

            return resultVO;
        }
    }

    private boolean checkUserNameAndCarUserName(ResultVO resultVO, UserDto userDto) {
        if(!userDto.getName().equals(userDto.getSettleAccountDto().getRecipient().getName())) {
            resultVO.setCode(ResultCodeEnum.ACCOUNT_CREATE_PARAM_ERROR.getCode());
            resultVO.setMsg(ResultCodeEnum.ACCOUNT_CREATE_PARAM_ERROR.getDisplayMsg());
            resultVO.setDisplayMsg(ResultCodeEnum.ACCOUNT_CREATE_PARAM_ERROR.getDisplayMsg());
            return true;
        }

        return false;
    }

    @Override
    public ResultVO<String> merchantCertifyAccountCreate(MerchantAccountCreateVo merchantAccountCreateVo, String sign) {
        ResultVO resultVO = new ResultVO();
        LOGGER.info("PaymentMerchantApiImpl merchantCertifyAccountCreate begin merchantAccountVo:{}, token:{}", JSONUtils.toJSON(merchantAccountCreateVo), sign);

        //防止连点 value随便设置
        if(!StringUtil.isEmpty(redisClient.get("merchantCreate"+merchantAccountCreateVo.getName()))) {
            resultVO.setCode(ResultCodeEnum.NOT_CONTINUOUS_CLICK.getCode());
            resultVO.setMsg(ResultCodeEnum.NOT_CONTINUOUS_CLICK.getDisplayMsg());
            return resultVO;
        }

        redisClient.set("merchantCreate"+merchantAccountCreateVo.getName(), "1", 5L);

        try {
            String type = merchantAccountCreateVo.getBusinessIdType().contains(BusinessTypeEnum.YIKUAIQIAN.getType()) ? Constants.YOP : Constants.PINGAN;
            String accountId = null;
            AccountDto accountDto = new AccountDto();
            accountDto.setBusinessIdType(merchantAccountCreateVo.getBusinessIdType());
            accountDto.setBusinessUserId(merchantAccountCreateVo.getBusinessUserId());
            ResultVO accountResult = accountService.createAccount(accountDto);

            if(!accountResult.getCode().equals(ResultCodeEnum.SUCCESS.getCode())) {
                accountId = accountResult.getResult().toString();
            } else {
                PayAccount payAccount = JSONUtils.parse2Object(accountResult.getResult().toString(), PayAccount.class);
                accountId = payAccount.getAccountId();
            }

            accountService.createThirdUserId(accountId, type, Constants.MERCHANT, merchantAccountCreateVo.getOpenBank(), merchantAccountCreateVo.getCustomerType());
            UserDto userDto = new UserDto();
            userDto.setCustomerType(merchantAccountCreateVo.getCustomerType());
            userDto.setThirdChannelType(type);
            Map<String, String> picMap = new HashMap<>(8);
            picMap.put(String.valueOf(PictureEnum.BUSINESS_CERT_PIC.getCode()), merchantAccountCreateVo.getBusinessCertPicUrl());
            picMap.put(String.valueOf(PictureEnum.LEGAL_CERT_FRONT.getCode()), merchantAccountCreateVo.getIdCardFrontUrl());
            picMap.put(String.valueOf(PictureEnum.LEGAL_CERT_BACK.getCode()), merchantAccountCreateVo.getIdCardBackUrl());

            if(StringUtils.isNotBlank(merchantAccountCreateVo.getBusinessLocationUrl())) {
                picMap.put(String.valueOf(PictureEnum.SHOP_ENTRANCE_PIC.getCode()), merchantAccountCreateVo.getBusinessLocationUrl());
            }

            if(StringUtils.isNotBlank(merchantAccountCreateVo.getOpenAccountLicenceUrl())) {
                picMap.put(String.valueOf(PictureEnum.OPEN_ACCOUNT_PIC.getCode()), merchantAccountCreateVo.getOpenAccountLicenceUrl());
            }

            accountService.UserInfoPicChange(accountId, picMap);
            userDto.setPicMap(picMap);
            userDto.setAccountType(AccountTypeEnum.BUSINESS.getType());
            userDto.setPicFmt(merchantAccountCreateVo.getPicFmt());
            userDto.setBusinessIdType(merchantAccountCreateVo.getBusinessIdType());
            userDto.setUserId(accountId);
            //添加联系人
            userDto.setContactInfos(merchantAccountCreateVo.getContactInfos());
            userDto.setBusinessIdType(merchantAccountCreateVo.getBusinessIdType());
            //创建账户
            userDto.setName(merchantAccountCreateVo.getName());
            userDto.setMobile(merchantAccountCreateVo.getMobile());
            userDto.setAddress(merchantAccountCreateVo.getAddress());
            userDto.setExtraMap(merchantAccountCreateVo.getExtra());
            IdentityInfo identityInfo = new IdentityInfo();
            identityInfo.setId(merchantAccountCreateVo.getCardId());
            identityInfo.setType(CertTypeEnum.ENTERPRISE_LICENSE.getCode());
            identityInfo.setValidUntil(merchantAccountCreateVo.getValidUntil());
            identityInfo.setValidFrom(merchantAccountCreateVo.getValidFrom());
            identityInfo.setIndustry(merchantAccountCreateVo.getIndustry());
            identityInfo.setOpenAccountLicenceNo(merchantAccountCreateVo.getOpenAccountLicenceNo());
            identityInfo.setBusinessProvince(merchantAccountCreateVo.getBusinessProvince());
            identityInfo.setBusinessCity(merchantAccountCreateVo.getBusinessCity());
            identityInfo.setBusinessDistrict(merchantAccountCreateVo.getBusinessDistrict());
            identityInfo.setBusinessAddress(merchantAccountCreateVo.getBusinessAddress());
            userDto.setIdentityInfo(identityInfo);
            userDto.setBusinessIdType(merchantAccountCreateVo.getBusinessIdType());
            //创建结算账户
            SettleAccountDto settleAccountDto = new SettleAccountDto();
            Recipient recipient = new Recipient();
            recipient.setType(merchantAccountCreateVo.getBankCardType());
            recipient.setAccount(merchantAccountCreateVo.getAccount());
            recipient.setName(merchantAccountCreateVo.getSettleName());
            recipient.setMobile(merchantAccountCreateVo.getSettleMobile());
            recipient.setOpenBank(merchantAccountCreateVo.getOpenBank());
            recipient.setOpenBankCode(merchantAccountCreateVo.getOpenBankCode());
            recipient.setCardType(merchantAccountCreateVo.getCardType());
            recipient.setSubBank(merchantAccountCreateVo.getSubBank());
            recipient.setSubBankCode(merchantAccountCreateVo.getSubBankCode());
            settleAccountDto.setUserId(accountId);
            settleAccountDto.setRecipient(recipient);
            settleAccountDto.setBusinessIdType(merchantAccountCreateVo.getBusinessIdType());
            settleAccountDto.setAccountType(AccountTypeEnum.BUSINESS.getType());
            settleAccountDto.setCallbackAddress(merchantAccountCreateVo.getCallbackAddress());
            settleAccountDto.setBusinessUserName(merchantAccountCreateVo.getBusinessUserName());
            userDto.setSettleAccountDto(settleAccountDto);
            userDto.setBeneficiaryInfos(merchantAccountCreateVo.getBeneficiaryInfos());
            userDto.setShareHolderInfos(merchantAccountCreateVo.getShareHolderInfos());
            userDto.setEnterprisePhone(merchantAccountCreateVo.getEnterprisePhone());
            userDto.setMerchantCategory(merchantAccountCreateVo.getMerchantCategory());
            userDto.setOperatorInfo(merchantAccountCreateVo.getOperatorInfo());
            userDto.setOldBusinessUserId(merchantAccountCreateVo.getOldBusinessUserId());

            if (checkUserNameAndCarUserName(resultVO, userDto)) {
                return resultVO;
            }

            resultVO = accountService.createAccount(userDto, merchantAccountCreateVo.getBusinessIdType(), Constants.MERCHANT, merchantAccountCreateVo.getAccountChannel());

            if(!resultVO.getCode().equals(ResultCodeEnum.SUCCESS.getCode())) {
                LOGGER.error("PaymentMerchantApiImpl merchantCreate create account error merchantAccountVo:{}", JSONUtils.toJSON(merchantAccountCreateVo));
                return resultVO;
            }

            // 上传图片
            resultVO = accountService.uploadPic(userDto, merchantAccountCreateVo.getBusinessIdType(), merchantAccountCreateVo.getAccountChannel());

            if(!resultVO.getCode().equals(ResultCodeEnum.SUCCESS.getCode())) {
                LOGGER.error("PaymentMerchantApiImpl merchantCreate upload error merchantAccountVo:{}", JSONUtils.toJSON(merchantAccountCreateVo));
                return resultVO;
            }

            LOGGER.info("PaymentMerchantApiImpl merchantCreate end token:{}", merchantAccountCreateVo.getName());
            OpenAccountVO openAccountVO = new OpenAccountVO();
            openAccountVO.setApplymentNo(accountId);
            resultVO.setResult(openAccountVO);
            return resultVO;
        }
        catch(Exception e) {
            LOGGER.error("PaymentMerchantApiImpl merchantCreate error merchantAccountVo=" + JSONUtils.toJSON(merchantAccountCreateVo), e);

            if(e instanceof PaymentException) {
                resultVO.setCode(((PaymentException) e).getErrCode());
                resultVO.setMsg(((PaymentException) e).getErrMsg());
            }
            else {
                resultVO.setCode(ResultCodeEnum.DEFAULT_ERROR.getCode());
                resultVO.setMsg(ResultCodeEnum.DEFAULT_ERROR.getDisplayMsg());
            }

            return resultVO;
        }
    }

    @Override
    public ResultVO<String> sendActiveCodeByPhoneNum(ActiveCodeVo activeCodeVo, String sign) {
        LOGGER.info("PaymentMerchantApiImpl#sendActiveCodeByPhoneNum activeCodeVo:{}", JSON.toJSONString(activeCodeVo));

        try {
            ActiveCodeDto activeCodeDto = new ActiveCodeDto();
            activeCodeDto.setAccountType(activeCodeVo.getAccountType());
            activeCodeDto.setBusinessIdType(activeCodeVo.getBusinessIdType());
            activeCodeDto.setPhoneNum(activeCodeVo.getPhoneNum());
            activeCodeDto.setBusinessUserId(activeCodeVo.getBusinessUserId());
            accountService.sendActiveCodeByPhoneNum(activeCodeDto);
        }
        catch(PaymentException e) {
            LOGGER.error(e.getErrMsg() ,e);
            return ResultVO.createError(e.getErrCode(), e.getErrMsg());
        }
        catch(UnsupportedOperationException e) {
            LOGGER.error(e.getMessage() ,e);
            return ResultVO.createError(ResultCodeEnum.UN_SUPPORT_METHOD);
        }

        return ResultVO.createSuccess();
    }

    @Override
    public ResultVO<Map<String, String>> bankCodeQuery() {
        return ResultVO.createSuccess(fuminBankCodeConfig.getBankMap());
    }

    /**
     * 银行查询
     */
    @Override
    public ResultVO<List<Pair>> bankQueryV2(BankQueryParam param) {
        LOGGER.info("PaymentMerchantApiImpl#bankQueryV2 param:{}", JSON.toJSONString(param));

        try {
            return ResultVO.createSuccess(baseBankService2.getBank(param));
        }
        catch(PaymentException ex) {
            LOGGER.error(ex.getErrMsg() + ", param=" + JSONUtils.toJSON(param), ex);
            return ResultVO.createError(ex.getErrCode(), ex.getErrMsg());
        }
    }

    @Override
    public ResultVO<Map<String, String>> merchantCategoryQuery() {
        return ResultVO.createSuccess(MerchantCategoryConfig.getMerchantCategoryMap());
    }

    @Override
    public ResultVO<String> personalSettleCardReBind(PersonalSettleCardBindVo personalSettleCardBindVo, String sign) {
        ResultVO resultVO = new ResultVO();
        LOGGER.info("PaymentMerchantApiImpl personalSettleCardReBind begin merchantAccountVo:{}, token:{}", JSONUtils.toJSON(personalSettleCardBindVo), personalSettleCardBindVo.getName());
        //防止连点 value随便设置
        if (!StringUtil.isEmpty(redisClient.get("merchantCreate"+personalSettleCardBindVo.getName()))){
            resultVO.setCode(ResultCodeEnum.NOT_CONTINUOUS_CLICK.getCode());
            resultVO.setMsg(ResultCodeEnum.NOT_CONTINUOUS_CLICK.getMsg());
            resultVO.setDisplayMsg(ResultCodeEnum.NOT_CONTINUOUS_CLICK.getDisplayMsg());
            return resultVO;
        }
        redisClient.set("merchantCreate"+personalSettleCardBindVo.getName(), "1", 5L);
        PersonalCardBindDto personalCardBindDto = new PersonalCardBindDto();
        personalCardBindDto.setCardType(personalSettleCardBindVo.getCardType());
        personalCardBindDto.setAccount(personalSettleCardBindVo.getAccount());
        personalCardBindDto.setAccountChannel(personalSettleCardBindVo.getAccountChannel());
        personalCardBindDto.setBusinessIdType(personalSettleCardBindVo.getBusinessIdType());
        personalCardBindDto.setBusinessUserId(personalSettleCardBindVo.getBusinessUserId());
        personalCardBindDto.setCardId(personalSettleCardBindVo.getCardId());
        personalCardBindDto.setCertType(personalSettleCardBindVo.getCertType());
        personalCardBindDto.setExtra(personalSettleCardBindVo.getExtra());
        personalCardBindDto.setMobile(personalSettleCardBindVo.getMobile());
        personalCardBindDto.setName(personalSettleCardBindVo.getName());
        personalCardBindDto.setOpenBank(personalSettleCardBindVo.getOpenBank());
        personalCardBindDto.setOpenBankCode(personalSettleCardBindVo.getOpenBankCode());
        personalCardBindDto.setBranchBankName(personalSettleCardBindVo.getBranchBank());
        personalCardBindDto.setBranchBankCd(personalSettleCardBindVo.getBranchBankCode());
        try {
            accountService.personalSettleCardReBind(personalCardBindDto);
        } catch (PaymentException e) {
            LOGGER.error("PaymentMerchantApiImpl personalSettleCardReBind error personalCardBindDto is {} : ", JSON.toJSONString(personalCardBindDto), e);
            return ResultVO.createError(e.getCodeEnum(), e.getErrMsg());
        }
        return ResultVO.createSuccess();
    }

    @Override
    public ResultVO<String> merchantSettleCardReBind(MerchantSettleCardBindVo merchantSettleCardBindVo, String sign) {
        ResultVO resultVO = new ResultVO();
        LOGGER.info("PaymentMerchantApiImpl merchantSettleCardReBind begin merchantSettleCardBindVo:{}, token:{}", JSONUtils.toJSON(merchantSettleCardBindVo), merchantSettleCardBindVo.getSettleName());

        //防止连点 value随便设置
        if(!StringUtil.isEmpty(redisClient.get("merchantCreate"+merchantSettleCardBindVo.getSettleName()))) {
            resultVO.setCode(ResultCodeEnum.NOT_CONTINUOUS_CLICK.getCode());
            resultVO.setMsg(ResultCodeEnum.NOT_CONTINUOUS_CLICK.getMsg());
            resultVO.setDisplayMsg(ResultCodeEnum.NOT_CONTINUOUS_CLICK.getDisplayMsg());
            return resultVO;
        }

        redisClient.set("merchantCreate"+merchantSettleCardBindVo.getSettleName(), "1", 5L);

        MerchantCardBindDto merchantCardBindDto = new MerchantCardBindDto();
        merchantCardBindDto.setCardType(merchantSettleCardBindVo.getCardType());
        merchantCardBindDto.setAccount(merchantSettleCardBindVo.getAccount());
        merchantCardBindDto.setAccountChannel(merchantSettleCardBindVo.getAccountChannel());
        merchantCardBindDto.setBusinessIdType(merchantSettleCardBindVo.getBusinessIdType());
        merchantCardBindDto.setBusinessUserId(merchantSettleCardBindVo.getBusinessUserId());
        merchantCardBindDto.setExtra(merchantSettleCardBindVo.getExtra());
        merchantCardBindDto.setMobile(merchantSettleCardBindVo.getMobile());
        merchantCardBindDto.setSettleName(merchantSettleCardBindVo.getSettleName());
        merchantCardBindDto.setOpenBank(merchantSettleCardBindVo.getOpenBank());
        merchantCardBindDto.setOpenBankCode(merchantSettleCardBindVo.getOpenBankCode());
        merchantCardBindDto.setBranchBankName(merchantSettleCardBindVo.getBranchBank());
        merchantCardBindDto.setBranchBankCd(merchantSettleCardBindVo.getBranchBankCode());
        merchantCardBindDto.setContactName(merchantSettleCardBindVo.getContactName());
        merchantCardBindDto.setContactIdCard(merchantSettleCardBindVo.getContactIdCard());
        merchantCardBindDto.setContactPhone(merchantSettleCardBindVo.getContactPhone());
        merchantCardBindDto.setCallback(merchantSettleCardBindVo.getCallback());
        merchantCardBindDto.setBusinessOrderNo(merchantSettleCardBindVo.getBusinessOrderNo());
        merchantCardBindDto.setCorporationName(merchantSettleCardBindVo.getCorporationName());
        merchantCardBindDto.setCorporationIdNo(merchantSettleCardBindVo.getCorporationIdNo());
        merchantCardBindDto.setCorporationPhone(merchantSettleCardBindVo.getCorporationPhone());
        merchantCardBindDto.setResendCode(merchantSettleCardBindVo.getResendCode());

        try {
            Integer applyStatus = accountService.merchantSettleCardReBind(merchantCardBindDto);
            return ResultVO.createSuccess(String.valueOf(applyStatus));
        }
        catch(PaymentException e) {
            LOGGER.error("PaymentMerchantApiImpl merchantSettleCardReBind error personalCardBindDto is {} : ", JSON.toJSONString(merchantCardBindDto), e);
            return ResultVO.createError(e.getErrCode(), e.getErrMsg());
        }
    }

    @Override
    public ResultVO<Map<String, String>> subBankCodeQuery(String bankName, String subBankName) {
        LOGGER.info("PaymentMerchantApiImpl#subBankCodeQuery start. bankName:{}, subBankName:{}", bankName, subBankName);
        List<SubBankCode> subBankCodes = subBankCodeService.likeByName(bankName, Objects.isNull(subBankName)?"":subBankName, 0, Constants.DEFAULT_PAGE_SIZE);
        Map<String, String> map = new HashMap<>();
        subBankCodes.stream().forEach(item -> {
            map.put(item.getName(), item.getCode());
        });
        return ResultVO.createSuccess(map);
    }

    /**
     * 支行查询
     *
     * @param param
     */
    @Override
    public ResultVO<List<Pair>> subBankQueryV2(SubBankQueryParam param) {
        LOGGER.info("PaymentMerchantApiImpl#subBankQueryV2 param:{}", JSON.toJSONString(param));

        try {
            return ResultVO.createSuccess(baseBankService2.getBranchBank(param));
        }
        catch(PaymentException ex) {
            LOGGER.error(ex.getErrMsg() + ", param=" + JSONUtils.toJSON(param), ex);
            return ResultVO.createError(ex.getErrCode(), ex.getErrMsg());
        }
    }

    /**
     * 查询账户流水
     *
     * @param queryAccountBalanceDO
     */
    @Override
    public ResultVO<QueryFuminRecordBo> queryBalanceRecord(QueryAccountBalanceDO queryAccountBalanceDO) {
        LOGGER.info("PaymentMerchantApiImpl.queryBalanceRecord. queryAccountBalanceDO：{}", JSONUtils.toJSON(queryAccountBalanceDO));

        try {
            return ResultVO.createSuccess(routeManager.queryBalanceRecord(queryAccountBalanceDO));
        }
        catch(Exception ex) {
            LOGGER.error("PaymentMerchantApiImpl.queryBalanceRecord error. message=" + ex.getMessage(), ex);
            return ResultVO.createError(ex.getMessage());
        }
    }

    /**
     * 获取授权人手机号
     *
     * @param param
     */
    @Override
    public ResultVO<OperatorPhoneBo> queryOperatorPhone(OperatorPhoneBo param) {
        LOGGER.info("PaymentMerchantApiImpl.queryOperatorPhone. param：{}", JSONUtils.toJSON(param));

        try {
            param.setPhone(userInfoService2.getOperatorPhone(param.getBusinessIdType() ,param.getBusinessId()));
            LOGGER.info("PaymentMerchantApiImpl.queryOperatorPhone. response：{}", JSONUtils.toJSON(param));
            return ResultVO.createSuccess(param);
        }
        catch(Exception ex) {
            LOGGER.error("PaymentMerchantApiImpl.queryOperatorPhone error. message=" + ex.getMessage() + ", param=" + JSONUtils.toJSON(param) ,ex);
            return ResultVO.createError("获取授权人手机号异常");
        }
    }

    /**
     * 行政区域查询
     */
    @Override
    public ResultVO<List<RegionVo>> regionQuery(RegionQueryParam param) {
        LOGGER.info("PaymentMerchantApiImpl#regionQuery param={}", JSONUtils.toJSON(param));
        XyyRegionParams xyyRegionParams = new XyyRegionParams();
        xyyRegionParams.setLevel(param.getLevel());
        xyyRegionParams.setParentCode(param.getParentCode());
        List<XyyRegionBusinessDto> items = regionService.queryRegion(xyyRegionParams);
        List<RegionVo> result = new ArrayList<>();

        for(XyyRegionBusinessDto item : items) {
            // 水星和火星
            if(Integer.valueOf("666666").equals(item.getAreaCode()) || Integer.valueOf("777777").equals(item.getAreaCode())) {
                continue;
            }

            result.add(RegionVo.build(item.getAreaCode(), item.getParentCode(), item.getAreaName() ,item.getLevel()));
        }

        return ResultVO.createSuccess(result);
    }

    /**
     * 会员间转账
     *
     * @param param
     */
    @Override
    public ResultVO<Boolean> accountTransfer(AccountTransferParam param) {
        LOGGER.info("PaymentMerchantApiImpl#accountTransfer param={}", JSONUtils.toJSON(param));

        try {

            separateOrderService2.accountTransfer(AccountTransferDto.builder().
                    transferType(param.getTransferType()).
                    businessIdType(param.getBusinessIdType()).
                    outAccountId(param.getOutAccountId()).
                    inAccountId(param.getInAccountId()).
                    amount(param.getAmount()).
                    businessOrderNo(param.getBusinessOrderNo()).
                    remark(param.getRemark()).
                    build());
        }
        catch(Exception ex) {
            LOGGER.error("PaymentMerchantApiImpl#accountTransfer error param={}", JSONUtils.toJSON(param), ex);

            if(ex instanceof PaymentException) {
                ResultVO<Boolean> resultVO = ResultVO.createError(((PaymentException) ex).getErrCode(), ((PaymentException) ex).getErrMsg());
                resultVO.setResult(Boolean.FALSE);
                return resultVO;
            }
            else {
                return ResultVO.createError(ResultCodeEnum.DEFAULT_ERROR, Boolean.FALSE);
            }
        }

        return ResultVO.createSuccess(Boolean.TRUE);
    }
    /**
     * 购物金转账-ec商城专用-会员间交易
     *
     * @param param
     */
    @Override
    public ResultVO<Boolean> virtualGoldTransfer(VirtualGoldTransferParam param) {
        LOGGER.info("PaymentMerchantApiImpl#virtualGoldTransfer param={}", JSONUtils.toJSON(param));
        String lockKey = RedisUtil.getVirtualGoldTransferPrefix(param.getBusinessUserId());
        try {
            // 1.checkParam
            checkVirtualGoldTransferParam(param);
            // 2.lock
            if (!redisUtil.tryLock(lockKey)) {
                throw new PaymentException(ResultCodeEnum.REPEAT_REQUEST);
            }
            // 3.获取转出、转入accountId
            String accountId = payAccountService.getAccountIdByBusiness(param.getBusinessIdType(), param.getBusinessUserId());
            if (StringUtils.isBlank(accountId)) {
                throw new PaymentException(ResultCodeEnum.USER_NOT_FOUND);
            }
            String ecBalanceAccountId = ApolloUtil.getProperty(Constants.EC_PINGAN_BALANCE_ACCOUNT_ID);
            if (StringUtils.isBlank(ecBalanceAccountId)) {
                LOGGER.error("virtualGoldTransfer ecBalanceAccountId is blank");
                throw new PaymentException(ResultCodeEnum.USER_NOT_FOUND);
            }
            Map<String, String> accountIds = getAccountIds(param.getTransferType(), accountId, ecBalanceAccountId);
            String outAccountId = accountIds.get("outAccountId");
            String inAccountId = accountIds.get("inAccountId");

            // 4.会员间交易
            ResultVO<Boolean> resultVO = separateOrderService2.accountTransferV2(AccountTransferDto.builder().
                    transferType(AccountTransferDto.TRANSFER_PAY).
                    businessIdType(param.getBusinessIdType()).
                    outAccountId(outAccountId).
                    inAccountId(inAccountId).
                    amount(param.getAmount()).
                    businessOrderNo(param.getBusinessOrderNo()).
                    remark(param.getRemark()).
                    build());
            return resultVO;
        } catch (Exception ex) {
            LOGGER.error("PaymentMerchantApiImpl#virtualGoldTransfer error param={}", JSONUtils.toJSON(param), ex);

            if (ex instanceof PaymentException) {
                ResultVO<Boolean> resultVO = ResultVO.createError(((PaymentException) ex).getErrCode(), ((PaymentException) ex).getErrMsg());
                resultVO.setResult(Boolean.FALSE);
                return resultVO;
            } else {
                return ResultVO.createError(ResultCodeEnum.DEFAULT_ERROR, Boolean.FALSE);
            }
        } finally {
            redisUtil.unLock(lockKey);
        }
    }

    public static Map<String, String> getAccountIds(String transferType, String accountId, String ecBalanceAccountId) {
        if (StringUtils.isBlank(accountId) || StringUtils.isBlank(ecBalanceAccountId)) {
            throw new IllegalArgumentException("Account IDs cannot be blank");
        }

        Map<String, String> accountIds = new HashMap<>();
        if (Objects.equals(VirtualGoldTransferParam.TYPE_0, transferType)) {
            // 转入
            accountIds.put("outAccountId", accountId);
            accountIds.put("inAccountId", ecBalanceAccountId);
        } else {
            // 转出
            accountIds.put("outAccountId", ecBalanceAccountId);
            accountIds.put("inAccountId", accountId);
        }
        return accountIds;
    }

    private void checkVirtualGoldTransferParam(VirtualGoldTransferParam param) throws PaymentException {
        if (param == null || StringUtils.isBlank(param.getTransferType()) || StringUtils.isBlank(param.getBusinessIdType()) ||
                param.getAmount() == null || param.getAmount() <= 0 ||
                StringUtils.isBlank(param.getBusinessOrderNo()) || StringUtils.isBlank(param.getBusinessUserId()) ||
                StringUtils.isBlank(param.getRemark())) {
            throw new PaymentException(ResultCodeEnum.PARAM_ERROR);
        }
        String transferType = param.getTransferType();
        if (!Objects.equals(VirtualGoldTransferParam.TYPE_0, transferType) && !Objects.equals(VirtualGoldTransferParam.TYPE_1, transferType)) {
            LOGGER.error("checkVirtualGoldTransferParam transferType error. transferType:{}", transferType);
            throw new PaymentException(ResultCodeEnum.PARAM_ERROR);
        }
    }
    @Override
    public ResultVO<QueryResultBo> queryTradeStatus(QueryTradeStatusParam param) {
        LOGGER.info("queryTradeStatus param={}", JSONUtils.toJSON(param));
        try{
            return separateOrderService2.queryTradeStatus(param);
        }catch (Exception ex) {
            LOGGER.error("queryTradeStatus error. param:{}", JSONUtils.toJSON(param), ex);
            return ResultVO.createError(ResultCodeEnum.DEFAULT_ERROR);
        }
    }

    @Override
    public ResultVO<Boolean> withdraw2(WithdrawAccountParam param) {
        LOGGER.info("PaymentMerchantApiImpl#withdraw2 param={}", JSONUtils.toJSON(param));
        try{
            WithdrawAccountDto withdrawAccountDto = new WithdrawAccountDto();
            BeanUtils.copyProperties(param, withdrawAccountDto);
            pinganAdapter.withdraw2(withdrawAccountDto);
        }catch (Exception ex) {
            LOGGER.error("PaymentMerchantApiImpl#withdraw2 error. param:{}", JSONUtils.toJSON(param), ex);
            return ResultVO.createError(ResultCodeEnum.DEFAULT_ERROR, Boolean.FALSE);
        }
        return ResultVO.createSuccess(Boolean.TRUE);
    }

    /**
     * 登记挂账
     *
     * @param param
     */
    @Override
    public ResultVO<Boolean> registerOrder(RegisterOrderParam param) {
        LOGGER.info("PaymentMerchantApiImpl#registerOrder param={}", JSONUtils.toJSON(param));

        try {
            separateOrderService2.registerOrder(RegisterOrderDto.builder().
                    businessIdType(param.getBusinessIdType()).
                    accountId(param.getAccountId()).
                    businessOrderNo(param.getBusinessOrderNo()).
                    amount(param.getAmount()).
                    remark(param.getRemark()).
                    build());
        }
        catch(Exception ex) {
            LOGGER.info("PaymentMerchantApiImpl#registerOrder error param=" + JSONUtils.toJSON(param), ex);

            if(ex instanceof PaymentException) {
                return ResultVO.createError(((PaymentException) ex).getErrCode(), ((PaymentException) ex).getErrMsg(), Boolean.FALSE);
            }
            else {
                return ResultVO.createError(ResultCodeEnum.DEFAULT_ERROR, Boolean.FALSE);
            }
        }

        return ResultVO.createSuccess(Boolean.TRUE);
    }

    public void checkCreateAccountParam(AccountVo accountVo, String sign) throws PaymentException, IllegalAccessException {
        if (accountVo==null){
            throw new PaymentException(ResultCodeEnum.PARAM_ERROR);
        }
        if (accountVo.getBusinessId() == null ||  accountVo.getInvoker() == null||accountVo.getBusinessIdType()==null){
            throw new PaymentException(ResultCodeEnum.PARAM_ERROR);
        }
        String publicKey = ApolloUtil.getProperty(accountVo.getInvoker().getType()+ Constants.PUBLIC);
        //验签
        if(!SignUtil.doCheck(accountVo, sign, publicKey)){
            throw new PaymentException(ResultCodeEnum.SIGN_ERROR);
        }
    }
    public void checkCreateAccountParam(AccountVoV1 accountVo, String sign) throws PaymentException, IllegalAccessException {
        if (accountVo==null){
            throw new PaymentException(ResultCodeEnum.PARAM_ERROR);
        }
        if (accountVo.getBusinessId() == null ||  accountVo.getInvoker() == null||accountVo.getBusinessIdType()==null){
            throw new PaymentException(ResultCodeEnum.PARAM_ERROR);
        }
        String publicKey = ApolloUtil.getProperty(accountVo.getInvoker()+ Constants.PUBLIC);
        //验签
        if(!SignUtil.doCheck(accountVo, sign, publicKey)){
            throw new PaymentException(ResultCodeEnum.SIGN_ERROR);
        }
    }
    @Override
    public ResultVO uploadPic(UploadPicVo uploadPicVo, String sign) {
        ResultVO resultVO = new ResultVO();
        LOGGER.info("PaymentMerchantApiImpl uploadPic begin merchantPicVo:{}", JSON.toJSON(uploadPicVo));
        if (uploadPicVo==null){
            LOGGER.warn("PaymentMerchantApiImpl uploadPic uploadPicVo is null");
            resultVO.setCode(ResultCodeEnum.PARAM_ERROR.getCode());
            resultVO.setMsg(ResultCodeEnum.PARAM_ERROR.getMsg());
            return resultVO;
        }

        try{
            if (AccountTypeEnum.BUSINESS.equals(uploadPicVo.getAccountTypeEnum())){
                if (!isValidMerchantPicParam(uploadPicVo)){
                    LOGGER.warn("PaymentMerchantApiImpl uploadPic BUSINESS param error uploadPicVo:{}", JSON.toJSON(uploadPicVo));
                    resultVO.setCode(ResultCodeEnum.PARAM_ERROR.getCode());
                    resultVO.setMsg(ResultCodeEnum.PARAM_ERROR.getMsg());
                    return resultVO;
                }
            }
            if (AccountTypeEnum.CUSTOMER.equals(uploadPicVo.getAccountTypeEnum())){
                if (!isValidPersonalPicParam(uploadPicVo)){
                    LOGGER.warn("PaymentMerchantApiImpl uploadPic CUSTOMER param error uploadPicVo:{}", JSON.toJSON(uploadPicVo));
                    resultVO.setCode(ResultCodeEnum.PARAM_ERROR.getCode());
                    resultVO.setMsg(ResultCodeEnum.PARAM_ERROR.getMsg());
                    return resultVO;
                }
            }
            String publicKey = ApolloUtil.getProperty(uploadPicVo.getInvoker()+".public_key");
            if(!SignUtil.doCheck(uploadPicVo, sign, publicKey)){
                LOGGER.warn("PaymentMerchantApiImpl uploadPic sign error businessId:{}", uploadPicVo.getBusinessId());
                return ResultVO.createSignError();
            }
            UserDto userDto = new UserDto();
            Map<String, byte[]> picMap = new HashMap<>(8);
            if (AccountTypeEnum.BUSINESS.equals(uploadPicVo.getAccountTypeEnum())){
                picMap.put(String.valueOf(PictureEnum.BUSINESS_CERT_PIC.getCode()), uploadPicVo.getBusinessCertPic());
                picMap.put(String.valueOf(PictureEnum.LEGAL_CERT_FRONT.getCode()), uploadPicVo.getIdCardFront());
                picMap.put(String.valueOf(PictureEnum.LEGAL_CERT_BACK.getCode()), uploadPicVo.getIdCardBack());
            }
            if (AccountTypeEnum.CUSTOMER.equals(uploadPicVo.getAccountTypeEnum())){
                picMap.put(String.valueOf(PictureEnum.PERSONAL_CERT_FRONT.getCode()), uploadPicVo.getPersonalIdCardFront());
                picMap.put(String.valueOf(PictureEnum.PERSONAL_CERT_BACK.getCode()), uploadPicVo.getPersonalIdCardBack());
            }
            userDto.setBusinessId(uploadPicVo.getBusinessId());
            userDto.setPicMap(new HashMap<>());
            userDto.setAccountType(uploadPicVo.getAccountTypeEnum().getType());
            userDto.setPicFmt(uploadPicVo.getPicFmt());
            userDto.setBusinessIdType(uploadPicVo.getBusinessIdTypeEnum().getType());
            resultVO = accountService.uploadPic(userDto, uploadPicVo.getBusinessIdTypeEnum().getType(), uploadPicVo.getAccountChannelEnum().getChannel());
            LOGGER.info("PaymentMerchantApiImpl uploadPic end merchantPicVo:{}, resultVO:{}", JSON.toJSON(uploadPicVo), JSON.toJSON(resultVO));
            return resultVO;
        }catch (PaymentException e){
            LOGGER.error("PaymentMerchantApiImpl uploadPic error merchantPicVo:{}", JSON.toJSON(uploadPicVo), e);
            resultVO.setCode(e.getErrCode());
            resultVO.setMsg(e.getErrMsg());
        }catch (Exception e){
            LOGGER.error("PaymentMerchantApiImpl uploadPic error merchantPicVo:{}", JSON.toJSON(uploadPicVo), e);
            resultVO.setCode(ResultCodeEnum.DEFAULT_ERROR.getCode());
            resultVO.setMsg(ResultCodeEnum.DEFAULT_ERROR.getMsg());
        }
        return resultVO;
    }

    /**
     * 添加联系人接口
     *
     * @param merchantContactVo
     * @param sign
     * @return
     */
    @Override
    public ResultVO<ContactBo> addContact(MerchantContactVo merchantContactVo, String sign) {
        LOGGER.info("PaymentMerchantApiImpl#addContact begin merchantContactVo:{}", JSON.toJSONString(merchantContactVo));
        return ResultVO.createError(ResultCodeEnum.UN_SUPPORT_METHOD);
    }

    @Override
    public ResultVO createMerchant(MerchantCreateVo merchantCreateVo, String sign) {
        ResultVO resultVO = new ResultVO();
        LOGGER.info("PaymentMerchantApiImpl createMerchant begin merchantCreateVo:{}", JSON.toJSON(merchantCreateVo));
        if (merchantCreateVo==null){
            LOGGER.warn("PaymentMerchantApiImpl createMerchant merchantCreateVo is null");
            resultVO.setCode(ResultCodeEnum.PARAM_ERROR.getCode());
            resultVO.setMsg(ResultCodeEnum.PARAM_ERROR.getMsg());
            return resultVO;
        }

        try{
            String publicKey = ApolloUtil.getProperty(merchantCreateVo.getInvoker()+".public_key");
            if(!SignUtil.doCheck(merchantCreateVo, sign, publicKey)){
                resultVO.setCode(ResultCodeEnum.SIGN_ERROR.getCode());
                resultVO.setMsg(ResultCodeEnum.SIGN_ERROR.getMsg());
                return resultVO;
            }
            UserDto userDto = new UserDto();
            userDto.setBusinessId(merchantCreateVo.getBusinessId());
            userDto.setName(merchantCreateVo.getName());
            userDto.setMobile(merchantCreateVo.getMobile());
            if (!StringUtil.isEmpty(merchantCreateVo.getEmail())){
                userDto.setEmail(merchantCreateVo.getEmail());
            }
            userDto.setAddress(merchantCreateVo.getAddress());
            IdentityInfo identityInfo = new IdentityInfo();
            identityInfo.setId(merchantCreateVo.getCardId());
            identityInfo.setType(CertTypeEnum.ENTERPRISE_LICENSE.getCode());
            identityInfo.setValidUntil(merchantCreateVo.getValidUntil());
            identityInfo.setValidFrom(merchantCreateVo.getValidFrom());
            identityInfo.setIndustry(merchantCreateVo.getIndustryEnum().getType());
            userDto.setIdentityInfo(identityInfo);
            userDto.setBusinessIdType(merchantCreateVo.getBusinessIdType().getType());
            resultVO = accountService.createAccount(userDto, merchantCreateVo.getBusinessIdType().getType(), Constants.MERCHANT, merchantCreateVo.getAccountChannelEnum().getChannel());
            LOGGER.info("PaymentMerchantApiImpl createMerchant end merchantCreateVo:{}, resultVo:{}", JSON.toJSON(merchantCreateVo), JSON.toJSON(resultVO));
            return resultVO;
        }catch (Exception e){
            LOGGER.error("PaymentMerchantApiImpl createUser merchantCreateVo:{}", JSON.toJSON(merchantCreateVo), e);
            resultVO.setCode(ResultCodeEnum.DEFAULT_ERROR.getCode());
            resultVO.setMsg(ResultCodeEnum.DEFAULT_ERROR.getMsg());
            return resultVO;
        }
    }

    @Override
    public ResultVO createPerson(PersonalCreateVo personalCreateVo, String sign){
        ResultVO resultVO = new ResultVO();
        LOGGER.info("PaymentMerchantApiImpl createPerson begin personalCreateVo:{}", personalCreateVo);
        if (personalCreateVo==null){
            LOGGER.warn("PaymentMerchantApiImpl createPerson personalCreateVo is null");
            resultVO.setCode(ResultCodeEnum.PARAM_ERROR.getCode());
            resultVO.setMsg(ResultCodeEnum.PARAM_ERROR.getMsg());
            return resultVO;
        }

        try{
            String publicKey = ApolloUtil.getProperty(personalCreateVo.getInvoker()+".public_key");
            if(!SignUtil.doCheck(personalCreateVo, sign, publicKey)){
                resultVO.setCode(ResultCodeEnum.SIGN_ERROR.getCode());
                resultVO.setMsg(ResultCodeEnum.SIGN_ERROR.getMsg());
                return resultVO;
            }
            UserDto userDto = new UserDto();
            userDto.setBusinessId(personalCreateVo.getBusinessId());
            userDto.setName(personalCreateVo.getName());
            userDto.setMobile(personalCreateVo.getMobile());
            userDto.setGender(personalCreateVo.getGenderEnum().toString());
            userDto.setAddress(personalCreateVo.getAddress());
            IdentityInfo identityInfo = new IdentityInfo();
            identityInfo.setId(personalCreateVo.getCardId());
            identityInfo.setType(CertTypeEnum.ID_CARD.getCode());
            identityInfo.setValidUntil(personalCreateVo.getValidUntil());
            identityInfo.setValidFrom(personalCreateVo.getValidFrom());
            identityInfo.setProfession(personalCreateVo.getProfessionEnum().getType());
            userDto.setIdentityInfo(identityInfo);
            userDto.setBusinessIdType(personalCreateVo.getBusinessIdType().getType());
            resultVO =  accountService.createAccount(userDto, personalCreateVo.getBusinessIdType().getType(), Constants.PERSONAL, personalCreateVo.getAccountChannelEnum().getChannel());
            LOGGER.info("PaymentMerchantApiImpl createPerson end personalCreateVo:{}, resultVO:{}", JSON.toJSON(personalCreateVo), JSON.toJSON(resultVO));
            return resultVO;
        }catch (Exception e){
            LOGGER.error("PaymentMerchantApiImpl createPerson personalCreateVo:{}", JSON.toJSON(personalCreateVo), e);
            resultVO.setCode(ResultCodeEnum.DEFAULT_ERROR.getCode());
            resultVO.setMsg(ResultCodeEnum.DEFAULT_ERROR.getMsg());
            return resultVO;
        }
    }

    @Override
    public ResultVO<Boolean> settle(SettleOrderVo2 settleOrderVo2) {
        String reqParam = JSON.toJSONString(settleOrderVo2);
        LOGGER.info("PaymentMerchantApiImpl settle param:{}", reqParam);
        try {
            SettleOrderDto settleOrderDto = SettleOrderDto.builder().build();
            BeanUtils.copyProperties(settleOrderVo2, settleOrderDto);
            separateOrderService2.settle(settleOrderDto);
            return ResultVO.createSuccess(Boolean.TRUE);
        } catch (PaymentException pe) {
            LOGGER.error("PaymentMerchantApiImpl settle error.  param:{} ", reqParam, pe);
            return ResultVO.createError(pe.getErrCode(), pe.getErrMsg(), Boolean.FALSE);
        } catch (Exception e) {
            LOGGER.error("PaymentMerchantApiImpl settle error.  param:{} ", reqParam, e);
            return ResultVO.createError(ResultCodeEnum.DEFAULT_ERROR, Boolean.FALSE);
        }
    }

    @Override
    public ResultVO queryAccount(QueryAccountVo queryAccountVo, String sign) {
        ResultVO resultVO = new ResultVO();
        LOGGER.info("PaymentMerchantApiImpl queryAccount begin queryAccountVo:{}", JSON.toJSON(queryAccountVo));

        if(queryAccountVo==null) {
            LOGGER.warn("PaymentMerchantApiImpl queryAccount queryAccountVo is null");
            resultVO.setCode(ResultCodeEnum.PARAM_ERROR.getCode());
            resultVO.setMsg(ResultCodeEnum.PARAM_ERROR.getMsg());
            return resultVO;
        }

        try {
            String publicKey = ApolloUtil.getProperty(queryAccountVo.getInvoker()+".public_key");

            if(!SignUtil.doCheck(queryAccountVo, sign, publicKey)) {
                resultVO.setCode(ResultCodeEnum.SIGN_ERROR.getCode());
                resultVO.setMsg(ResultCodeEnum.SIGN_ERROR.getMsg());
                return resultVO;
            }

            resultVO = accountService.queryAccount(queryAccountVo.getBusinessId(), queryAccountVo.getBusinessIdType(),
                    queryAccountVo.getAccountChannelEnum().getChannel(), queryAccountVo.getBalanceAccountType());
            LOGGER.info("PaymentMerchantApiImpl queryAccount end queryAccountVo:{}, resultVO:{}", JSON.toJSON(queryAccountVo), JSON.toJSON(resultVO));
            return resultVO;
        }
        catch(Exception e){
            LOGGER.error("PaymentMerchantApiImpl getUserBalance merchantQueryVo:{}", JSON.toJSON(queryAccountVo), e);
            resultVO.setCode(ResultCodeEnum.DEFAULT_ERROR.getCode());
            resultVO.setMsg(ResultCodeEnum.DEFAULT_ERROR.getMsg());
            return resultVO;
        }
    }

    @Override
    public ResultVO<CustAcctInfoVo> queryCustAcctId(String accountId) {
        LOGGER.info("PaymentMerchantApiImpl queryCustAcctId accountId:{}", accountId);
        try {
            CustAcctInfoVo custAcctInfoVo = pinganAdapter.queryCustAcctId(accountId);
            LOGGER.info("PaymentMerchantApiImpl queryCustAcctId result:{}", JSON.toJSONString(custAcctInfoVo));
            return ResultVO.createSuccess(custAcctInfoVo);
        } catch (Exception e) {
            LOGGER.error("PaymentMerchantApiImpl queryCustAcctId error. accountId:{} ", accountId, e);
            return ResultVO.createError(ResultCodeEnum.DEFAULT_ERROR);
        }
    }

    @Override
    public ResultVO<UserBo> queryAccountByAccountNo(String accountNo, String balanceAccountType) {
        ResultVO resultVO = new ResultVO();
        if (StringUtils.isBlank(accountNo) || StringUtils.isBlank(balanceAccountType)) {
            LOGGER.warn("PaymentMerchantApiImpl queryAccountByAccountNo param error {} {} ", accountNo, balanceAccountType);
            resultVO.setCode(ResultCodeEnum.PARAM_ERROR.getCode());
            resultVO.setMsg(ResultCodeEnum.PARAM_ERROR.getMsg());
            return resultVO;
        }
        QueryAccountDto queryAccountDto = new QueryAccountDto();
        queryAccountDto.setThirdUserId(accountNo);
        queryAccountDto.setBalanceAccountType(balanceAccountType);
        queryAccountDto.setUserId(accountNo);
        LOGGER.info("PaymentMerchantApiImpl queryAccountByAccountNo begin queryAccountDto:{}", queryAccountDto);
        try {
            UserBo userBo = pinganAdapter.queryAccount(queryAccountDto);
            resultVO.setResult(userBo);
            LOGGER.info("PaymentMerchantApiImpl queryAccount end queryAccountVo:{}, resultVO:{}", JSON.toJSON(queryAccountDto), JSON.toJSON(resultVO));
            return resultVO;
        } catch (Exception e) {
            LOGGER.error("PaymentMerchantApiImpl queryAccountByAccountNo queryAccountDto:{}", JSON.toJSON(queryAccountDto), e);
            resultVO.setCode(ResultCodeEnum.DEFAULT_ERROR.getCode());
            resultVO.setMsg(ResultCodeEnum.DEFAULT_ERROR.getMsg());
            return resultVO;
        }
    }

    /**
     * 创建用户结算账户接口
     */
    @Override
    public ResultVO<SettleAccountBo> createSettleAccount(SettleAccountsCreateVo settleAccountsCreateVo, String sign) {
        LOGGER.info("PaymentMerchantApiImpl#createSettleAccount begin SettleAccountsCreateVo:{}", JSON.toJSONString(settleAccountsCreateVo));
        return ResultVO.createError(ResultCodeEnum.UN_SUPPORT_METHOD);
    }

    /**
     * 查询用户结算账户接口
     *
     * @param settleAccountsQueryVo
     * @param sign
     * @return
     */
    @Override
    public ResultVO<SettleAccountBo> querySettleAccounts(SettleAccountsQueryVo settleAccountsQueryVo, String sign) {
        LOGGER.info("PaymentMerchantApiImpl#querySettleAccounts begin SettleAccountsQueryVo:{}", JSON.toJSONString(settleAccountsQueryVo));
        return ResultVO.createError(ResultCodeEnum.UN_SUPPORT_METHOD);
    }

    public boolean isValidMerchantPicParam(UploadPicVo uploadPicVo){
        if(uploadPicVo.getBusinessCertPic()==null || uploadPicVo.getIdCardBack()==null || uploadPicVo.getIdCardFront()==null) {
            return false;
        }

        return true;
    }

    public boolean isValidPersonalPicParam(UploadPicVo uploadPicVo){
        if(uploadPicVo.getPersonalIdCardBack()==null || uploadPicVo.getPersonalIdCardFront()==null) {
            return false;
        }

        return true;
    }
}
